package lovedna.net;
import nme.display.Bitmap;
import nme.display.BitmapData;
import nme.display.LoaderInfo;
import nme.events.Event;
import nme.events.IOErrorEvent;
import nme.events.ProgressEvent;
import nme.events.SecurityErrorEvent;
import nme.events.TimerEvent;
import nme.net.URLRequest;
import nme.utils.Timer;
/**
 * ...
 * @author liwei
 * 现在版本js加载不会报ioerror错误
 * 须要改browser.display.BitmapData 和 browser.display.Loader两个类
 */
class ImageLoader
{
	// 加载器最大个数
	private var _queueMax:Int;
	// /当前加载器个数
	private var _queueCount:Int;
	// 请求列表
	private var _requestList:Array<LRequest>;
	// 请求地址索引
	private var _urlDict:Hash<Bool>;
	// 加载总个数
	private var _count : Int;
	private var _update : Bool;
	private var _index:Int;
	private var _timer:Timer;
	public function new(?count:Int=5) 
	{
		setMax(count);
		_queueCount = 0;
		_requestList = new Array<LRequest>();
		_urlDict = new Hash<Bool>();
		_count = 0;
		_update = false;
		_index = 0;
		_timer = new Timer(1, 1);
		_timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerhandler);
	}
	
	private function timerhandler(e:TimerEvent):Void 
	{
		start();
	}
	/**
	 * 
	 * @param	url 加载地址
	 * @param	priority 加载优先级 越大越先加载
	 */
	public function load(url:String, priority:Int = -1):Void {
		if (url.length == 0) return;
		if (_urlDict.get(url) == true) return;
		if (priority < 0) {
			priority = _index--;
		}
		_urlDict.set(url, true);
		_requestList.push(new LRequest(url, priority));
		_update = true;
		_count = _requestList.length;
		if (_timer.running) {
			return;
		}
		_timer.start();
	}
	public function stop():Void {
		var len:Int = _requestList.length;
		while (len-->0) {
			_requestList.pop();
		}
	}
	public function setMax(value:Int):Void {
		if (value < 1) {
			value = 1;
		}
		if (value > 30) {
			value > 30;
		}
		_queueMax = value;
	}
	private function start():Void {
		if (_update) {
			_requestList.sort(sort);
		}
		_update = false;
		loadNext();
	}
	private function sort(x:LRequest, y:LRequest):Int {
		var p1:Int = x.priority;
		var p2:Int = y.priority;
		if (p1 > p2) {
			return 1;
		}else if (p1 < p2) {
			return -1;
		}else {
			return 0;
		}
	}
	private function loadNext() : Void {
		if (_requestList.length == 0) {
			_index = 0;
			return;
		}
		var loader:LLoader = getloader();
		if (loader == null) {
			return;
		}
		var r : LRequest = _requestList.pop();
		if (r == null) return;
		var request : URLRequest = new URLRequest(r.url);
		loader.lload(request);
		loadNext();
	}
	private function getloader():LLoader {
		if (_queueCount < _queueMax) {
			var loader:LLoader = new LLoader();
			_queueCount++;
			addEvent(loader, true);
			return loader;
		}
		return null;
	}
	private function addEvent(target:LLoader, add:Bool = true):Void {
		if (target == null) return;
		if (add) {
			target.contentLoaderInfo.addEventListener(Event.COMPLETE, complete);
			target.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, io);
			target.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progress);
			target.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, security);
			target.contentLoaderInfo.addEventListener(Event.OPEN, open);
		}else {
			target.contentLoaderInfo.removeEventListener(Event.COMPLETE, complete);
			target.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, io);
			target.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, progress);
			target.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, security);
			target.contentLoaderInfo.removeEventListener(Event.OPEN, open);
		}
	}
	
	private function open(e:Event):Void 
	{
		if (onOpen != null) {
			var info:LoaderInfo = cast e.target;
			var loader:LLoader = cast info.loader;
			Reflect.callMethod(this, onOpen, [loader.url]);
		}
	}
	
	public var onOpen:String->Void ;
	public var onComplete:String->BitmapData->Void;
	public var onError:String->Void;
	public var onProgress: String->Float->Float->Void ;
	public var onSecurity:String->Void;
	
	private function security(e:SecurityErrorEvent):Void 
	{
		var info:LoaderInfo = cast e.target;
		var loader:LLoader = cast info.loader;
		if (onSecurity != null) {
			Reflect.callMethod(this, onSecurity, [loader.url]);
		}
		finish(loader);
	}
	
	private function progress(e:ProgressEvent):Void 
	{
		if (onProgress != null) {
			var info:LoaderInfo = cast e.target;
			var loader:LLoader = cast info.loader;
			Reflect.callMethod(this, onProgress, [loader.url,e.bytesLoaded,e.bytesTotal]);
		}
	}
	
	private function io(e:IOErrorEvent):Void 
	{
		var info:LoaderInfo = cast e.target;
		var loader:LLoader = cast info.loader;
		if (onError != null) {
			Reflect.callMethod(this, onError, [loader.url]);
		}
		finish(loader);
	}
	
	private function complete(e:Event):Void 
	{
		var info:LoaderInfo = cast e.target;
		var loader:LLoader = cast info.loader;
		var url:String = loader.url;
		var bm:Bitmap = cast info.content;
		var error:Bool = false;
		if (bm != null) {
			if (bm.width == 0) {
				error = true;
			}
		}else {
			error = true;
		}
		if (error) {
			if (onError != null) {
				Reflect.callMethod(this, onError, [url]);
			}
		}else {
			
		}
		if (onComplete != null) {
			Reflect.callMethod(this, onComplete, [url,bm.bitmapData]);
		}
		finish(loader);
	}
	private function finish(target:LLoader):Void {
		if (target == null) return;
		_urlDict.remove(target.url);
		_count = _requestList.length;
		addEvent(target, false);
		target = null;
		_queueCount--;
		loadNext();
	}
	
	private function get_count():Int 
	{
		return _count;
	}
	
	public var count(get_count, null):Int;
}
